﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Threading;
using System.Diagnostics;
using System.Threading;
using Microsoft.Practices.Composite.Events;

namespace PJ.Presentation
{
    public abstract class BaseViewModel : DependencyObject, IViewModel
    {
        private IView m_View;
        private readonly IEventAggregator m_EventAggregator;


        public BaseViewModel(IView view, IEventAggregator aggregator)
        {
            m_EventAggregator = aggregator;
            if (view != null)
            {
                m_View = view;
                View.ViewModel = this;
            }
        }

        public IEventAggregator EventAggregator
        {
            get 
            {
                if (m_EventAggregator == null)
                    throw new ArgumentNullException();
                return m_EventAggregator; 
            }
        }

        public IView View
        {
            get
            {
                if (m_View == null)
                    throw new ArgumentNullException();
                return m_View;
            }
            set
            {
                if (m_View != value)
                {
                    if (m_View != null && value != null)
                        throw new ArgumentNullException();
                    else
                        m_View = value;
                }
            }
        }

        protected object ThreadSafeGetValue(DependencyProperty dp)
        {
            return this.Dispatcher.Invoke(
                    System.Windows.Threading.DispatcherPriority.Background,
                    (DispatcherOperationCallback)delegate { return GetValue(dp); });
        }

        protected void ThreadSafeSetValue(DependencyProperty dp, object val)
        {
            this.Dispatcher.BeginInvoke(
                    System.Windows.Threading.DispatcherPriority.Background,
                    (SendOrPostCallback)delegate { SetValue(dp, val); });
        }

        protected object ThreadUnsafeGetValue(DependencyProperty dp)
        {
            AssertOnUIThread();
            return this.GetValue(dp);
        }
        protected void ThreadUnsafeSetValue(DependencyProperty dp, object val)
        {
            AssertOnUIThread();
            this.SetValue(dp, val);
        }

        [Conditional("Debug")]
        protected void AssertOnUIThread()
        {
            Debug.Assert(this.Dispatcher == Dispatcher.CurrentDispatcher, "Call must be made on UI thread.");
        }

        public virtual void Dispose()
        {
            m_View = null;
        }
    }
}
